package system

import (
	consts2 "MoSkeleton/config/consts"
	"MoSkeleton/framework/core/consts"
	"MoSkeleton/framework/core/dto/response"
	"MoSkeleton/framework/core/moerrors"
	"MoSkeleton/framework/utils"
	"MoSkeleton/global"
	"MoSkeleton/models/system"
	"MoSkeleton/services/base"
	s1 "MoSkeleton/web/pogos/request/system"
	system2 "MoSkeleton/web/pogos/response/system"
	"bytes"
	"errors"
	"github.com/samber/lo"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"strconv"
)

type SysPostService struct {
	base.BaseService
}

/*
	 select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark
			from sys_post

<where>

		<if test="postCode != null and postCode != ''">
			AND post_code like concat('%', #{postCode}, '%')
		</if>
		<if test="status != null and status != ''">
			AND status = #{status}
		</if>
		<if test="postName != null and postName != ''">
			AND post_name like concat('%', #{postName}, '%')
		</if>
	</where>
*/
func (p *SysPostService) GetPostPage(postReq *s1.SysPostPageReq) (*response.PageResult, error) {
	db := p.getPostListVo(postReq)
	result := make([]*system2.SysPostItemResp, 0)
	var total int64
	if err := db.Count(&total).Offset(postReq.Offset()).Limit(postReq.Limit()).Find(&result).Error; err != nil {
		return nil, err
	}
	pageResult := response.NewFromPageInfoAndData(&postReq.PageInfo, &result, total)
	return pageResult, nil
}

/*
select id, post_code, post_name, post_sort, status, created_by, created_at, remark

	from sys_post
*/
func (p *SysPostService) GetPostAll() (*[]*system2.SysPostItemResp, error) {
	result := make([]*system2.SysPostItemResp, 0)
	selecctFields := "id, post_code, post_name, post_sort, status, created_by, created_at, remark"
	if err := base.BaseDb.Model(&system.SysPost{}).Select(selecctFields).Find(&result).Error; err != nil {
		return nil, err
	}
	return &result, nil
}

func (p *SysPostService) GetPostById(id uint64) (*system2.SysPostItemResp, error) {
	itemResp := &system2.SysPostItemResp{}
	if err := base.BaseDb.Model(&system.SysPost{}).Where("id = ?", id).First(&itemResp).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return itemResp, nil
}

func (p *SysPostService) AddPost(addReq *s1.SysPostAddReq) (bool, error) {
	sysPost := &system.SysPost{}

	if err := utils.CopyStruct(sysPost, addReq); err != nil {
		return false, err
	}
	result := base.BaseDb.Create(sysPost)
	return result.RowsAffected > 0, result.Error
}

func (p *SysPostService) UpdatePostById(updateReq *s1.SysPostUpdateReq) (bool, error) {
	sysPost := &system.SysPost{}

	if err := utils.CopyStruct(sysPost, updateReq); err != nil {
		return false, err
	}
	return true, sysPost.UpdatePostById(nil)
}

func (p *SysPostService) DeletePostByIds(ids []uint64) (bool, error) {
	userPost := new(system.SysUserPost)
	count, err := userPost.GetFirstUserPostByPostIds(ids)
	if err != nil {
		global.MoLogger.Info("获取岗位使用数量失败", zap.Error(err))
		return false, err
	}
	if count > 0 {
		return false, moerrors.NewValidateError(consts.CommDeleteFailCode, "该岗位已被用户使用，无法删除")
	}
	result := base.BaseDb.Model(&system.SysPost{}).Delete(&system.SysPost{}, ids)
	return result.RowsAffected > 0, result.Error
}

/*
select p.post_id, p.post_name, p.post_code
from sys_post p

	left join sys_user_post up on up.post_id = p.post_id
	left join sys_user u on u.user_id = up.user_id

where u.user_id = #{userId}
*/
func (p *SysPostService) GetPostNamesByUserId(userId uint64) ([]string, error) {
	postResps := make([]*system2.SysPostItemResp, 0)
	selectFields := "p.id, p.post_name, p.post_code"
	db := p.GetDb(nil).Table("sys_post p").Select(selectFields)
	if err := db.Joins("left join sys_user_post up on up.post_id = p.id").
		Joins("left join sys_user u on u.id = up.user_id").
		Where("u.id = ?", userId).Find(&postResps).Error; err != nil {
		return nil, err
	}
	return lo.Map(postResps, func(item *system2.SysPostItemResp, index int) string {
		return item.PostName
	}), nil
}

func (p *SysPostService) ExportPost(postReq *s1.SysPostPageReq) (*bytes.Buffer, error) {
	db := p.getPostListVo(postReq)
	itemsResp := make([]*system2.SysPostItemResp, 0)
	if err := db.Find(&itemsResp).Error; err != nil {
		return nil, err
	}

	titles := []string{"岗位编号", "岗位编码", "岗位名称", "岗位排序", "状态"}
	exportFile := utils.NewExportExcelFile()
	return exportFile.Export(consts2.Excel_Sheet_Post, &titles, func(row, col int, colTitle string) (value any, ok bool, err error) {
		if len(itemsResp) <= row {
			return "", false, nil
		}
		itemResp := itemsResp[row]
		switch col {
		case 0:
			return "'" + strconv.FormatUint(itemResp.ID, 10), true, nil
		case 1:
			return itemResp.PostCode, true, nil
		case 2:
			return itemResp.PostName, true, nil
		case 3:
			return itemResp.PostSort, true, nil
		case 4:
			if itemResp.Status == consts2.U_NORMAL {
				return "正常", true, nil
			} else {
				return "停用", true, nil
			}
		}
		return "", false, nil
	})
}

func (p *SysPostService) getPostListVo(postReq *s1.SysPostPageReq) *gorm.DB {
	db := base.BaseDb.Model(&system.SysPost{})
	if postReq.PostCode != "" {
		db.Where("post_code like concat('%', ?, '%')", postReq.PostCode)
	}
	if postReq.Status != "" {
		db.Where("status = ?", postReq.Status)
	}
	if postReq.PostName != "" {
		db.Where("post_name like concat('%', ?, '%')", postReq.PostName)
	}
	return db
}
